/*
    Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements.  See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership.  The ASF licenses this file
    to you under the Apache License, Version 2.0 (the
    "License"); you may not use this file except in compliance
    with the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing,
    software distributed under the License is distributed on an
    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    KIND, either express or implied.  See the License for the
    specific language governing permissions and limitations
    under the License.
*/

var AES = function() {
  "use strict";

  var AES = function() {
    this.Nk = 0;
    this.Nr = 0;
    this.mode = 0;
    this.fkey = [];
    this.rkey = [];
    this.f = [];
  };

  // AES constants
  AES.ECB = 0;
  AES.CBC = 1;
  AES.CFB1 = 2;
  AES.CFB2 = 3;
  AES.CFB4 = 5;
  AES.OFB1 = 14;
  AES.OFB2 = 15;
  AES.OFB4 = 17;
  AES.OFB8 = 21;
  AES.OFB16 = 29;
  AES.CTR1 = 30;
  AES.CTR2 = 31;
  AES.CTR4 = 33;
  AES.CTR8 = 37;
  AES.CTR16 = 45;

  AES.prototype = {
    /* reset cipher */
    reset: function(m, iv) {
      /* reset mode, or reset iv */
      var i;

      this.mode = m;

      for (i = 0; i < 16; i++) {
        this.f[i] = 0;
      }

      if (this.mode != AES.ECB && iv !== null) {
        for (i = 0; i < 16; i++) {
          this.f[i] = iv[i];
        }
      }
    },

    getreg: function() {
      var ir = [],
        i;

      for (i = 0; i < 16; i++) {
        ir[i] = this.f[i];
      }

      return ir;
    },

    increment: function() {
      var i;

      for (i = 0; i < 16; i++) {
        this.f[i]++;

        if ((this.f[i] & 0xff) != 0) {
          break;
        }
      }
    },

    /* Initialise cipher */
    init: function(m, nk, key, iv) {
      /* Key=16 bytes */
      /* Key Scheduler. Create expanded encryption key */
      var CipherKey = [],
        b = [],
        i,
        j,
        k,
        N,
        nr;

      nk /= 4;

      if (nk != 4 && nk != 6 && nk != 8) {
        return false;
      }

      nr = 6 + nk;

      this.Nk = nk;
      this.Nr = nr;

      this.reset(m, iv);
      N = 4 * (nr + 1);

      for (i = j = 0; i < nk; i++, j += 4) {
        for (k = 0; k < 4; k++) {
          b[k] = key[j + k];
        }
        CipherKey[i] = AES.pack(b);
      }

      for (i = 0; i < nk; i++) {
        this.fkey[i] = CipherKey[i];
      }

      for (j = nk, k = 0; j < N; j += nk, k++) {
        this.fkey[j] =
          this.fkey[j - nk] ^ AES.SubByte(AES.ROTL24(this.fkey[j - 1])) ^ (AES.rco[k] & 0xff);

        if (nk <= 6) {
          for (i = 1; i < nk && i + j < N; i++) {
            this.fkey[i + j] = this.fkey[i + j - nk] ^ this.fkey[i + j - 1];
          }
        } else {
          for (i = 1; i < 4 && i + j < N; i++) {
            this.fkey[i + j] = this.fkey[i + j - nk] ^ this.fkey[i + j - 1];
          }
          if (j + 4 < N) {
            this.fkey[j + 4] = this.fkey[j + 4 - nk] ^ AES.SubByte(this.fkey[j + 3]);
          }
          for (i = 5; i < nk && i + j < N; i++) {
            this.fkey[i + j] = this.fkey[i + j - nk] ^ this.fkey[i + j - 1];
          }
        }
      }

      /* now for the expanded decrypt key in reverse order */

      for (j = 0; j < 4; j++) {
        this.rkey[j + N - 4] = this.fkey[j];
      }

      for (i = 4; i < N - 4; i += 4) {
        k = N - 4 - i;
        for (j = 0; j < 4; j++) {
          this.rkey[k + j] = AES.InvMixCol(this.fkey[i + j]);
        }
      }

      for (j = N - 4; j < N; j++) {
        this.rkey[j - N + 4] = this.fkey[j];
      }
    },

    /* Encrypt a single block */
    ecb_encrypt: function(buff) {
      var b = [],
        p = [],
        q = [],
        t,
        i,
        j,
        k;

      for (i = j = 0; i < 4; i++, j += 4) {
        for (k = 0; k < 4; k++) {
          b[k] = buff[j + k];
        }
        p[i] = AES.pack(b);
        p[i] ^= this.fkey[i];
      }

      k = 4;

      /* State alternates between p and q */
      for (i = 1; i < this.Nr; i++) {
        q[0] =
          this.fkey[k] ^
          AES.ftable[p[0] & 0xff] ^
          AES.ROTL8(AES.ftable[(p[1] >>> 8) & 0xff]) ^
          AES.ROTL16(AES.ftable[(p[2] >>> 16) & 0xff]) ^
          AES.ROTL24(AES.ftable[(p[3] >>> 24) & 0xff]);
        q[1] =
          this.fkey[k + 1] ^
          AES.ftable[p[1] & 0xff] ^
          AES.ROTL8(AES.ftable[(p[2] >>> 8) & 0xff]) ^
          AES.ROTL16(AES.ftable[(p[3] >>> 16) & 0xff]) ^
          AES.ROTL24(AES.ftable[(p[0] >>> 24) & 0xff]);
        q[2] =
          this.fkey[k + 2] ^
          AES.ftable[p[2] & 0xff] ^
          AES.ROTL8(AES.ftable[(p[3] >>> 8) & 0xff]) ^
          AES.ROTL16(AES.ftable[(p[0] >>> 16) & 0xff]) ^
          AES.ROTL24(AES.ftable[(p[1] >>> 24) & 0xff]);
        q[3] =
          this.fkey[k + 3] ^
          AES.ftable[p[3] & 0xff] ^
          AES.ROTL8(AES.ftable[(p[0] >>> 8) & 0xff]) ^
          AES.ROTL16(AES.ftable[(p[1] >>> 16) & 0xff]) ^
          AES.ROTL24(AES.ftable[(p[2] >>> 24) & 0xff]);

        k += 4;
        for (j = 0; j < 4; j++) {
          t = p[j];
          p[j] = q[j];
          q[j] = t;
        }
      }

      /* Last Round */

      q[0] =
        this.fkey[k] ^
        (AES.fbsub[p[0] & 0xff] & 0xff) ^
        AES.ROTL8(AES.fbsub[(p[1] >>> 8) & 0xff] & 0xff) ^
        AES.ROTL16(AES.fbsub[(p[2] >>> 16) & 0xff] & 0xff) ^
        AES.ROTL24(AES.fbsub[(p[3] >>> 24) & 0xff] & 0xff);

      q[1] =
        this.fkey[k + 1] ^
        (AES.fbsub[p[1] & 0xff] & 0xff) ^
        AES.ROTL8(AES.fbsub[(p[2] >>> 8) & 0xff] & 0xff) ^
        AES.ROTL16(AES.fbsub[(p[3] >>> 16) & 0xff] & 0xff) ^
        AES.ROTL24(AES.fbsub[(p[0] >>> 24) & 0xff] & 0xff);

      q[2] =
        this.fkey[k + 2] ^
        (AES.fbsub[p[2] & 0xff] & 0xff) ^
        AES.ROTL8(AES.fbsub[(p[3] >>> 8) & 0xff] & 0xff) ^
        AES.ROTL16(AES.fbsub[(p[0] >>> 16) & 0xff] & 0xff) ^
        AES.ROTL24(AES.fbsub[(p[1] >>> 24) & 0xff] & 0xff);

      q[3] =
        this.fkey[k + 3] ^
        (AES.fbsub[p[3] & 0xff] & 0xff) ^
        AES.ROTL8(AES.fbsub[(p[0] >>> 8) & 0xff] & 0xff) ^
        AES.ROTL16(AES.fbsub[(p[1] >>> 16) & 0xff] & 0xff) ^
        AES.ROTL24(AES.fbsub[(p[2] >>> 24) & 0xff] & 0xff);

      for (i = j = 0; i < 4; i++, j += 4) {
        b = AES.unpack(q[i]);
        for (k = 0; k < 4; k++) {
          buff[j + k] = b[k];
        }
      }
    },

    /* Decrypt a single block */
    ecb_decrypt: function(buff) {
      var b = [],
        p = [],
        q = [],
        t,
        i,
        j,
        k;

      for (i = j = 0; i < 4; i++, j += 4) {
        for (k = 0; k < 4; k++) {
          b[k] = buff[j + k];
        }
        p[i] = AES.pack(b);
        p[i] ^= this.rkey[i];
      }

      k = 4;

      /* State alternates between p and q */
      for (i = 1; i < this.Nr; i++) {
        q[0] =
          this.rkey[k] ^
          AES.rtable[p[0] & 0xff] ^
          AES.ROTL8(AES.rtable[(p[3] >>> 8) & 0xff]) ^
          AES.ROTL16(AES.rtable[(p[2] >>> 16) & 0xff]) ^
          AES.ROTL24(AES.rtable[(p[1] >>> 24) & 0xff]);
        q[1] =
          this.rkey[k + 1] ^
          AES.rtable[p[1] & 0xff] ^
          AES.ROTL8(AES.rtable[(p[0] >>> 8) & 0xff]) ^
          AES.ROTL16(AES.rtable[(p[3] >>> 16) & 0xff]) ^
          AES.ROTL24(AES.rtable[(p[2] >>> 24) & 0xff]);
        q[2] =
          this.rkey[k + 2] ^
          AES.rtable[p[2] & 0xff] ^
          AES.ROTL8(AES.rtable[(p[1] >>> 8) & 0xff]) ^
          AES.ROTL16(AES.rtable[(p[0] >>> 16) & 0xff]) ^
          AES.ROTL24(AES.rtable[(p[3] >>> 24) & 0xff]);
        q[3] =
          this.rkey[k + 3] ^
          AES.rtable[p[3] & 0xff] ^
          AES.ROTL8(AES.rtable[(p[2] >>> 8) & 0xff]) ^
          AES.ROTL16(AES.rtable[(p[1] >>> 16) & 0xff]) ^
          AES.ROTL24(AES.rtable[(p[0] >>> 24) & 0xff]);

        k += 4;

        for (j = 0; j < 4; j++) {
          t = p[j];
          p[j] = q[j];
          q[j] = t;
        }
      }

      /* Last Round */

      q[0] =
        this.rkey[k] ^
        (AES.rbsub[p[0] & 0xff] & 0xff) ^
        AES.ROTL8(AES.rbsub[(p[3] >>> 8) & 0xff] & 0xff) ^
        AES.ROTL16(AES.rbsub[(p[2] >>> 16) & 0xff] & 0xff) ^
        AES.ROTL24(AES.rbsub[(p[1] >>> 24) & 0xff] & 0xff);
      q[1] =
        this.rkey[k + 1] ^
        (AES.rbsub[p[1] & 0xff] & 0xff) ^
        AES.ROTL8(AES.rbsub[(p[0] >>> 8) & 0xff] & 0xff) ^
        AES.ROTL16(AES.rbsub[(p[3] >>> 16) & 0xff] & 0xff) ^
        AES.ROTL24(AES.rbsub[(p[2] >>> 24) & 0xff] & 0xff);
      q[2] =
        this.rkey[k + 2] ^
        (AES.rbsub[p[2] & 0xff] & 0xff) ^
        AES.ROTL8(AES.rbsub[(p[1] >>> 8) & 0xff] & 0xff) ^
        AES.ROTL16(AES.rbsub[(p[0] >>> 16) & 0xff] & 0xff) ^
        AES.ROTL24(AES.rbsub[(p[3] >>> 24) & 0xff] & 0xff);
      q[3] =
        this.rkey[k + 3] ^
        (AES.rbsub[p[3] & 0xff] & 0xff) ^
        AES.ROTL8(AES.rbsub[(p[2] >>> 8) & 0xff] & 0xff) ^
        AES.ROTL16(AES.rbsub[(p[1] >>> 16) & 0xff] & 0xff) ^
        AES.ROTL24(AES.rbsub[(p[0] >>> 24) & 0xff] & 0xff);

      for (i = j = 0; i < 4; i++, j += 4) {
        b = AES.unpack(q[i]);
        for (k = 0; k < 4; k++) {
          buff[j + k] = b[k];
        }
      }
    },

    /* Encrypt using selected mode of operation */
    encrypt: function(buff) {
      var st = [],
        bytes,
        fell_off,
        j;

      // Supported Modes of Operation

      fell_off = 0;

      switch (this.mode) {
        case AES.ECB:
          this.ecb_encrypt(buff);
          return 0;

        case AES.CBC:
          for (j = 0; j < 16; j++) {
            buff[j] ^= this.f[j];
          }
          this.ecb_encrypt(buff);
          for (j = 0; j < 16; j++) {
            this.f[j] = buff[j];
          }
          return 0;

        case AES.CFB1:
        case AES.CFB2:
        case AES.CFB4:
          bytes = this.mode - AES.CFB1 + 1;
          for (j = 0; j < bytes; j++) {
            fell_off = (fell_off << 8) | this.f[j];
          }
          for (j = 0; j < 16; j++) {
            st[j] = this.f[j];
          }
          for (j = bytes; j < 16; j++) {
            this.f[j - bytes] = this.f[j];
          }
          this.ecb_encrypt(st);
          for (j = 0; j < bytes; j++) {
            buff[j] ^= st[j];
            this.f[16 - bytes + j] = buff[j];
          }
          return fell_off;

        case AES.OFB1:
        case AES.OFB2:
        case AES.OFB4:
        case AES.OFB8:
        case AES.OFB16:
          bytes = this.mode - AES.OFB1 + 1;
          this.ecb_encrypt(this.f);
          for (j = 0; j < bytes; j++) {
            buff[j] ^= this.f[j];
          }
          return 0;

        case AES.CTR1:
        case AES.CTR2:
        case AES.CTR4:
        case AES.CTR8:
        case AES.CTR16:
          bytes = this.mode - AES.CTR1 + 1;
          for (j = 0; j < 16; j++) {
            st[j] = this.f[j];
          }
          this.ecb_encrypt(st);
          for (j = 0; j < bytes; j++) {
            buff[j] ^= st[j];
          }
          this.increment();
          return 0;

        default:
          return 0;
      }
    },

    /* Decrypt using selected mode of operation */
    decrypt: function(buff) {
      var st = [],
        bytes,
        fell_off,
        j;

      // Supported modes of operation
      fell_off = 0;
      switch (this.mode) {
        case AES.ECB:
          this.ecb_decrypt(buff);
          return 0;

        case AES.CBC:
          for (j = 0; j < 16; j++) {
            st[j] = this.f[j];
            this.f[j] = buff[j];
          }
          this.ecb_decrypt(buff);
          for (j = 0; j < 16; j++) {
            buff[j] ^= st[j];
            st[j] = 0;
          }
          return 0;

        case AES.CFB1:
        case AES.CFB2:
        case AES.CFB4:
          bytes = this.mode - AES.CFB1 + 1;
          for (j = 0; j < bytes; j++) {
            fell_off = (fell_off << 8) | this.f[j];
          }
          for (j = 0; j < 16; j++) {
            st[j] = this.f[j];
          }
          for (j = bytes; j < 16; j++) {
            this.f[j - bytes] = this.f[j];
          }
          this.ecb_encrypt(st);
          for (j = 0; j < bytes; j++) {
            this.f[16 - bytes + j] = buff[j];
            buff[j] ^= st[j];
          }
          return fell_off;

        case AES.OFB1:
        case AES.OFB2:
        case AES.OFB4:
        case AES.OFB8:
        case AES.OFB16:
          bytes = this.mode - AES.OFB1 + 1;
          this.ecb_encrypt(this.f);
          for (j = 0; j < bytes; j++) {
            buff[j] ^= this.f[j];
          }
          return 0;

        case AES.CTR1:
        case AES.CTR2:
        case AES.CTR4:
        case AES.CTR8:
        case AES.CTR16:
          bytes = this.mode - AES.CTR1 + 1;
          for (j = 0; j < 16; j++) {
            st[j] = this.f[j];
          }
          this.ecb_encrypt(st);
          for (j = 0; j < bytes; j++) {
            buff[j] ^= st[j];
          }
          this.increment();
          return 0;

        default:
          return 0;
      }
    },

    /* Clean up and delete left-overs */
    end: function() {
      // clean up
      var i;

      for (i = 0; i < 4 * (this.Nr + 1); i++) {
        this.fkey[i] = this.rkey[i] = 0;
      }

      for (i = 0; i < 16; i++) {
        this.f[i] = 0;
      }
    },
  };

  /* static functions */

  AES.ROTL8 = function(x) {
    return (x << 8) | (x >>> 24);
  };

  AES.ROTL16 = function(x) {
    return (x << 16) | (x >>> 16);
  };

  AES.ROTL24 = function(x) {
    return (x << 24) | (x >>> 8);
  };

  AES.pack = function(b) {
    /* pack 4 bytes into a 32-bit Word */
    return ((b[3] & 0xff) << 24) | ((b[2] & 0xff) << 16) | ((b[1] & 0xff) << 8) | (b[0] & 0xff);
  };

  AES.unpack = function(a) {
    /* unpack bytes from a word */
    var b = [];
    b[0] = a & 0xff;
    b[1] = (a >>> 8) & 0xff;
    b[2] = (a >>> 16) & 0xff;
    b[3] = (a >>> 24) & 0xff;
    return b;
  };

  AES.bmul = function(x, y) {
    /* x.y= AntiLog(Log(x) + Log(y)) */
    var ix = x & 0xff,
      iy = y & 0xff,
      lx = AES.ltab[ix] & 0xff,
      ly = AES.ltab[iy] & 0xff;

    if (x !== 0 && y !== 0) {
      return AES.ptab[(lx + ly) % 255];
    } else {
      return 0;
    }
  };

  //  if (x && y)

  AES.SubByte = function(a) {
    var b = AES.unpack(a);
    b[0] = AES.fbsub[b[0] & 0xff];
    b[1] = AES.fbsub[b[1] & 0xff];
    b[2] = AES.fbsub[b[2] & 0xff];
    b[3] = AES.fbsub[b[3] & 0xff];
    return AES.pack(b);
  };

  AES.product = function(x, y) {
    /* dot product of two 4-byte arrays */
    var xb = AES.unpack(x),
      yb = AES.unpack(y);

    return (
      (AES.bmul(xb[0], yb[0]) ^
        AES.bmul(xb[1], yb[1]) ^
        AES.bmul(xb[2], yb[2]) ^
        AES.bmul(xb[3], yb[3])) &
      0xff
    );
  };

  AES.InvMixCol = function(x) {
    /* matrix Multiplication */
    var b = [],
      y,
      m;

    m = AES.pack(AES.InCo);
    b[3] = AES.product(m, x);
    m = AES.ROTL24(m);
    b[2] = AES.product(m, x);
    m = AES.ROTL24(m);
    b[1] = AES.product(m, x);
    m = AES.ROTL24(m);
    b[0] = AES.product(m, x);
    y = AES.pack(b);

    return y;
  };

  AES.InCo = [0xb, 0xd, 0x9, 0xe]; /* Inverse Coefficients */
  AES.rco = [1, 2, 4, 8, 16, 32, 64, 128, 27, 54, 108, 216, 171, 77, 154, 47];

  AES.ptab = [
    1,
    3,
    5,
    15,
    17,
    51,
    85,
    255,
    26,
    46,
    114,
    150,
    161,
    248,
    19,
    53,
    95,
    225,
    56,
    72,
    216,
    115,
    149,
    164,
    247,
    2,
    6,
    10,
    30,
    34,
    102,
    170,
    229,
    52,
    92,
    228,
    55,
    89,
    235,
    38,
    106,
    190,
    217,
    112,
    144,
    171,
    230,
    49,
    83,
    245,
    4,
    12,
    20,
    60,
    68,
    204,
    79,
    209,
    104,
    184,
    211,
    110,
    178,
    205,
    76,
    212,
    103,
    169,
    224,
    59,
    77,
    215,
    98,
    166,
    241,
    8,
    24,
    40,
    120,
    136,
    131,
    158,
    185,
    208,
    107,
    189,
    220,
    127,
    129,
    152,
    179,
    206,
    73,
    219,
    118,
    154,
    181,
    196,
    87,
    249,
    16,
    48,
    80,
    240,
    11,
    29,
    39,
    105,
    187,
    214,
    97,
    163,
    254,
    25,
    43,
    125,
    135,
    146,
    173,
    236,
    47,
    113,
    147,
    174,
    233,
    32,
    96,
    160,
    251,
    22,
    58,
    78,
    210,
    109,
    183,
    194,
    93,
    231,
    50,
    86,
    250,
    21,
    63,
    65,
    195,
    94,
    226,
    61,
    71,
    201,
    64,
    192,
    91,
    237,
    44,
    116,
    156,
    191,
    218,
    117,
    159,
    186,
    213,
    100,
    172,
    239,
    42,
    126,
    130,
    157,
    188,
    223,
    122,
    142,
    137,
    128,
    155,
    182,
    193,
    88,
    232,
    35,
    101,
    175,
    234,
    37,
    111,
    177,
    200,
    67,
    197,
    84,
    252,
    31,
    33,
    99,
    165,
    244,
    7,
    9,
    27,
    45,
    119,
    153,
    176,
    203,
    70,
    202,
    69,
    207,
    74,
    222,
    121,
    139,
    134,
    145,
    168,
    227,
    62,
    66,
    198,
    81,
    243,
    14,
    18,
    54,
    90,
    238,
    41,
    123,
    141,
    140,
    143,
    138,
    133,
    148,
    167,
    242,
    13,
    23,
    57,
    75,
    221,
    124,
    132,
    151,
    162,
    253,
    28,
    36,
    108,
    180,
    199,
    82,
    246,
    1,
  ];
  AES.ltab = [
    0,
    255,
    25,
    1,
    50,
    2,
    26,
    198,
    75,
    199,
    27,
    104,
    51,
    238,
    223,
    3,
    100,
    4,
    224,
    14,
    52,
    141,
    129,
    239,
    76,
    113,
    8,
    200,
    248,
    105,
    28,
    193,
    125,
    194,
    29,
    181,
    249,
    185,
    39,
    106,
    77,
    228,
    166,
    114,
    154,
    201,
    9,
    120,
    101,
    47,
    138,
    5,
    33,
    15,
    225,
    36,
    18,
    240,
    130,
    69,
    53,
    147,
    218,
    142,
    150,
    143,
    219,
    189,
    54,
    208,
    206,
    148,
    19,
    92,
    210,
    241,
    64,
    70,
    131,
    56,
    102,
    221,
    253,
    48,
    191,
    6,
    139,
    98,
    179,
    37,
    226,
    152,
    34,
    136,
    145,
    16,
    126,
    110,
    72,
    195,
    163,
    182,
    30,
    66,
    58,
    107,
    40,
    84,
    250,
    133,
    61,
    186,
    43,
    121,
    10,
    21,
    155,
    159,
    94,
    202,
    78,
    212,
    172,
    229,
    243,
    115,
    167,
    87,
    175,
    88,
    168,
    80,
    244,
    234,
    214,
    116,
    79,
    174,
    233,
    213,
    231,
    230,
    173,
    232,
    44,
    215,
    117,
    122,
    235,
    22,
    11,
    245,
    89,
    203,
    95,
    176,
    156,
    169,
    81,
    160,
    127,
    12,
    246,
    111,
    23,
    196,
    73,
    236,
    216,
    67,
    31,
    45,
    164,
    118,
    123,
    183,
    204,
    187,
    62,
    90,
    251,
    96,
    177,
    134,
    59,
    82,
    161,
    108,
    170,
    85,
    41,
    157,
    151,
    178,
    135,
    144,
    97,
    190,
    220,
    252,
    188,
    149,
    207,
    205,
    55,
    63,
    91,
    209,
    83,
    57,
    132,
    60,
    65,
    162,
    109,
    71,
    20,
    42,
    158,
    93,
    86,
    242,
    211,
    171,
    68,
    17,
    146,
    217,
    35,
    32,
    46,
    137,
    180,
    124,
    184,
    38,
    119,
    153,
    227,
    165,
    103,
    74,
    237,
    222,
    197,
    49,
    254,
    24,
    13,
    99,
    140,
    128,
    192,
    247,
    112,
    7,
  ];
  AES.fbsub = [
    99,
    124,
    119,
    123,
    242,
    107,
    111,
    197,
    48,
    1,
    103,
    43,
    254,
    215,
    171,
    118,
    202,
    130,
    201,
    125,
    250,
    89,
    71,
    240,
    173,
    212,
    162,
    175,
    156,
    164,
    114,
    192,
    183,
    253,
    147,
    38,
    54,
    63,
    247,
    204,
    52,
    165,
    229,
    241,
    113,
    216,
    49,
    21,
    4,
    199,
    35,
    195,
    24,
    150,
    5,
    154,
    7,
    18,
    128,
    226,
    235,
    39,
    178,
    117,
    9,
    131,
    44,
    26,
    27,
    110,
    90,
    160,
    82,
    59,
    214,
    179,
    41,
    227,
    47,
    132,
    83,
    209,
    0,
    237,
    32,
    252,
    177,
    91,
    106,
    203,
    190,
    57,
    74,
    76,
    88,
    207,
    208,
    239,
    170,
    251,
    67,
    77,
    51,
    133,
    69,
    249,
    2,
    127,
    80,
    60,
    159,
    168,
    81,
    163,
    64,
    143,
    146,
    157,
    56,
    245,
    188,
    182,
    218,
    33,
    16,
    255,
    243,
    210,
    205,
    12,
    19,
    236,
    95,
    151,
    68,
    23,
    196,
    167,
    126,
    61,
    100,
    93,
    25,
    115,
    96,
    129,
    79,
    220,
    34,
    42,
    144,
    136,
    70,
    238,
    184,
    20,
    222,
    94,
    11,
    219,
    224,
    50,
    58,
    10,
    73,
    6,
    36,
    92,
    194,
    211,
    172,
    98,
    145,
    149,
    228,
    121,
    231,
    200,
    55,
    109,
    141,
    213,
    78,
    169,
    108,
    86,
    244,
    234,
    101,
    122,
    174,
    8,
    186,
    120,
    37,
    46,
    28,
    166,
    180,
    198,
    232,
    221,
    116,
    31,
    75,
    189,
    139,
    138,
    112,
    62,
    181,
    102,
    72,
    3,
    246,
    14,
    97,
    53,
    87,
    185,
    134,
    193,
    29,
    158,
    225,
    248,
    152,
    17,
    105,
    217,
    142,
    148,
    155,
    30,
    135,
    233,
    206,
    85,
    40,
    223,
    140,
    161,
    137,
    13,
    191,
    230,
    66,
    104,
    65,
    153,
    45,
    15,
    176,
    84,
    187,
    22,
  ];
  AES.rbsub = [
    82,
    9,
    106,
    213,
    48,
    54,
    165,
    56,
    191,
    64,
    163,
    158,
    129,
    243,
    215,
    251,
    124,
    227,
    57,
    130,
    155,
    47,
    255,
    135,
    52,
    142,
    67,
    68,
    196,
    222,
    233,
    203,
    84,
    123,
    148,
    50,
    166,
    194,
    35,
    61,
    238,
    76,
    149,
    11,
    66,
    250,
    195,
    78,
    8,
    46,
    161,
    102,
    40,
    217,
    36,
    178,
    118,
    91,
    162,
    73,
    109,
    139,
    209,
    37,
    114,
    248,
    246,
    100,
    134,
    104,
    152,
    22,
    212,
    164,
    92,
    204,
    93,
    101,
    182,
    146,
    108,
    112,
    72,
    80,
    253,
    237,
    185,
    218,
    94,
    21,
    70,
    87,
    167,
    141,
    157,
    132,
    144,
    216,
    171,
    0,
    140,
    188,
    211,
    10,
    247,
    228,
    88,
    5,
    184,
    179,
    69,
    6,
    208,
    44,
    30,
    143,
    202,
    63,
    15,
    2,
    193,
    175,
    189,
    3,
    1,
    19,
    138,
    107,
    58,
    145,
    17,
    65,
    79,
    103,
    220,
    234,
    151,
    242,
    207,
    206,
    240,
    180,
    230,
    115,
    150,
    172,
    116,
    34,
    231,
    173,
    53,
    133,
    226,
    249,
    55,
    232,
    28,
    117,
    223,
    110,
    71,
    241,
    26,
    113,
    29,
    41,
    197,
    137,
    111,
    183,
    98,
    14,
    170,
    24,
    190,
    27,
    252,
    86,
    62,
    75,
    198,
    210,
    121,
    32,
    154,
    219,
    192,
    254,
    120,
    205,
    90,
    244,
    31,
    221,
    168,
    51,
    136,
    7,
    199,
    49,
    177,
    18,
    16,
    89,
    39,
    128,
    236,
    95,
    96,
    81,
    127,
    169,
    25,
    181,
    74,
    13,
    45,
    229,
    122,
    159,
    147,
    201,
    156,
    239,
    160,
    224,
    59,
    77,
    174,
    42,
    245,
    176,
    200,
    235,
    187,
    60,
    131,
    83,
    153,
    97,
    23,
    43,
    4,
    126,
    186,
    119,
    214,
    38,
    225,
    105,
    20,
    99,
    85,
    33,
    12,
    125,
  ];
  AES.ftable = [
    0xa56363c6,
    0x847c7cf8,
    0x997777ee,
    0x8d7b7bf6,
    0xdf2f2ff,
    0xbd6b6bd6,
    0xb16f6fde,
    0x54c5c591,
    0x50303060,
    0x3010102,
    0xa96767ce,
    0x7d2b2b56,
    0x19fefee7,
    0x62d7d7b5,
    0xe6abab4d,
    0x9a7676ec,
    0x45caca8f,
    0x9d82821f,
    0x40c9c989,
    0x877d7dfa,
    0x15fafaef,
    0xeb5959b2,
    0xc947478e,
    0xbf0f0fb,
    0xecadad41,
    0x67d4d4b3,
    0xfda2a25f,
    0xeaafaf45,
    0xbf9c9c23,
    0xf7a4a453,
    0x967272e4,
    0x5bc0c09b,
    0xc2b7b775,
    0x1cfdfde1,
    0xae93933d,
    0x6a26264c,
    0x5a36366c,
    0x413f3f7e,
    0x2f7f7f5,
    0x4fcccc83,
    0x5c343468,
    0xf4a5a551,
    0x34e5e5d1,
    0x8f1f1f9,
    0x937171e2,
    0x73d8d8ab,
    0x53313162,
    0x3f15152a,
    0xc040408,
    0x52c7c795,
    0x65232346,
    0x5ec3c39d,
    0x28181830,
    0xa1969637,
    0xf05050a,
    0xb59a9a2f,
    0x907070e,
    0x36121224,
    0x9b80801b,
    0x3de2e2df,
    0x26ebebcd,
    0x6927274e,
    0xcdb2b27f,
    0x9f7575ea,
    0x1b090912,
    0x9e83831d,
    0x742c2c58,
    0x2e1a1a34,
    0x2d1b1b36,
    0xb26e6edc,
    0xee5a5ab4,
    0xfba0a05b,
    0xf65252a4,
    0x4d3b3b76,
    0x61d6d6b7,
    0xceb3b37d,
    0x7b292952,
    0x3ee3e3dd,
    0x712f2f5e,
    0x97848413,
    0xf55353a6,
    0x68d1d1b9,
    0x0,
    0x2cededc1,
    0x60202040,
    0x1ffcfce3,
    0xc8b1b179,
    0xed5b5bb6,
    0xbe6a6ad4,
    0x46cbcb8d,
    0xd9bebe67,
    0x4b393972,
    0xde4a4a94,
    0xd44c4c98,
    0xe85858b0,
    0x4acfcf85,
    0x6bd0d0bb,
    0x2aefefc5,
    0xe5aaaa4f,
    0x16fbfbed,
    0xc5434386,
    0xd74d4d9a,
    0x55333366,
    0x94858511,
    0xcf45458a,
    0x10f9f9e9,
    0x6020204,
    0x817f7ffe,
    0xf05050a0,
    0x443c3c78,
    0xba9f9f25,
    0xe3a8a84b,
    0xf35151a2,
    0xfea3a35d,
    0xc0404080,
    0x8a8f8f05,
    0xad92923f,
    0xbc9d9d21,
    0x48383870,
    0x4f5f5f1,
    0xdfbcbc63,
    0xc1b6b677,
    0x75dadaaf,
    0x63212142,
    0x30101020,
    0x1affffe5,
    0xef3f3fd,
    0x6dd2d2bf,
    0x4ccdcd81,
    0x140c0c18,
    0x35131326,
    0x2fececc3,
    0xe15f5fbe,
    0xa2979735,
    0xcc444488,
    0x3917172e,
    0x57c4c493,
    0xf2a7a755,
    0x827e7efc,
    0x473d3d7a,
    0xac6464c8,
    0xe75d5dba,
    0x2b191932,
    0x957373e6,
    0xa06060c0,
    0x98818119,
    0xd14f4f9e,
    0x7fdcdca3,
    0x66222244,
    0x7e2a2a54,
    0xab90903b,
    0x8388880b,
    0xca46468c,
    0x29eeeec7,
    0xd3b8b86b,
    0x3c141428,
    0x79dedea7,
    0xe25e5ebc,
    0x1d0b0b16,
    0x76dbdbad,
    0x3be0e0db,
    0x56323264,
    0x4e3a3a74,
    0x1e0a0a14,
    0xdb494992,
    0xa06060c,
    0x6c242448,
    0xe45c5cb8,
    0x5dc2c29f,
    0x6ed3d3bd,
    0xefacac43,
    0xa66262c4,
    0xa8919139,
    0xa4959531,
    0x37e4e4d3,
    0x8b7979f2,
    0x32e7e7d5,
    0x43c8c88b,
    0x5937376e,
    0xb76d6dda,
    0x8c8d8d01,
    0x64d5d5b1,
    0xd24e4e9c,
    0xe0a9a949,
    0xb46c6cd8,
    0xfa5656ac,
    0x7f4f4f3,
    0x25eaeacf,
    0xaf6565ca,
    0x8e7a7af4,
    0xe9aeae47,
    0x18080810,
    0xd5baba6f,
    0x887878f0,
    0x6f25254a,
    0x722e2e5c,
    0x241c1c38,
    0xf1a6a657,
    0xc7b4b473,
    0x51c6c697,
    0x23e8e8cb,
    0x7cdddda1,
    0x9c7474e8,
    0x211f1f3e,
    0xdd4b4b96,
    0xdcbdbd61,
    0x868b8b0d,
    0x858a8a0f,
    0x907070e0,
    0x423e3e7c,
    0xc4b5b571,
    0xaa6666cc,
    0xd8484890,
    0x5030306,
    0x1f6f6f7,
    0x120e0e1c,
    0xa36161c2,
    0x5f35356a,
    0xf95757ae,
    0xd0b9b969,
    0x91868617,
    0x58c1c199,
    0x271d1d3a,
    0xb99e9e27,
    0x38e1e1d9,
    0x13f8f8eb,
    0xb398982b,
    0x33111122,
    0xbb6969d2,
    0x70d9d9a9,
    0x898e8e07,
    0xa7949433,
    0xb69b9b2d,
    0x221e1e3c,
    0x92878715,
    0x20e9e9c9,
    0x49cece87,
    0xff5555aa,
    0x78282850,
    0x7adfdfa5,
    0x8f8c8c03,
    0xf8a1a159,
    0x80898909,
    0x170d0d1a,
    0xdabfbf65,
    0x31e6e6d7,
    0xc6424284,
    0xb86868d0,
    0xc3414182,
    0xb0999929,
    0x772d2d5a,
    0x110f0f1e,
    0xcbb0b07b,
    0xfc5454a8,
    0xd6bbbb6d,
    0x3a16162c,
  ];
  AES.rtable = [
    0x50a7f451,
    0x5365417e,
    0xc3a4171a,
    0x965e273a,
    0xcb6bab3b,
    0xf1459d1f,
    0xab58faac,
    0x9303e34b,
    0x55fa3020,
    0xf66d76ad,
    0x9176cc88,
    0x254c02f5,
    0xfcd7e54f,
    0xd7cb2ac5,
    0x80443526,
    0x8fa362b5,
    0x495ab1de,
    0x671bba25,
    0x980eea45,
    0xe1c0fe5d,
    0x2752fc3,
    0x12f04c81,
    0xa397468d,
    0xc6f9d36b,
    0xe75f8f03,
    0x959c9215,
    0xeb7a6dbf,
    0xda595295,
    0x2d83bed4,
    0xd3217458,
    0x2969e049,
    0x44c8c98e,
    0x6a89c275,
    0x78798ef4,
    0x6b3e5899,
    0xdd71b927,
    0xb64fe1be,
    0x17ad88f0,
    0x66ac20c9,
    0xb43ace7d,
    0x184adf63,
    0x82311ae5,
    0x60335197,
    0x457f5362,
    0xe07764b1,
    0x84ae6bbb,
    0x1ca081fe,
    0x942b08f9,
    0x58684870,
    0x19fd458f,
    0x876cde94,
    0xb7f87b52,
    0x23d373ab,
    0xe2024b72,
    0x578f1fe3,
    0x2aab5566,
    0x728ebb2,
    0x3c2b52f,
    0x9a7bc586,
    0xa50837d3,
    0xf2872830,
    0xb2a5bf23,
    0xba6a0302,
    0x5c8216ed,
    0x2b1ccf8a,
    0x92b479a7,
    0xf0f207f3,
    0xa1e2694e,
    0xcdf4da65,
    0xd5be0506,
    0x1f6234d1,
    0x8afea6c4,
    0x9d532e34,
    0xa055f3a2,
    0x32e18a05,
    0x75ebf6a4,
    0x39ec830b,
    0xaaef6040,
    0x69f715e,
    0x51106ebd,
    0xf98a213e,
    0x3d06dd96,
    0xae053edd,
    0x46bde64d,
    0xb58d5491,
    0x55dc471,
    0x6fd40604,
    0xff155060,
    0x24fb9819,
    0x97e9bdd6,
    0xcc434089,
    0x779ed967,
    0xbd42e8b0,
    0x888b8907,
    0x385b19e7,
    0xdbeec879,
    0x470a7ca1,
    0xe90f427c,
    0xc91e84f8,
    0x0,
    0x83868009,
    0x48ed2b32,
    0xac70111e,
    0x4e725a6c,
    0xfbff0efd,
    0x5638850f,
    0x1ed5ae3d,
    0x27392d36,
    0x64d90f0a,
    0x21a65c68,
    0xd1545b9b,
    0x3a2e3624,
    0xb1670a0c,
    0xfe75793,
    0xd296eeb4,
    0x9e919b1b,
    0x4fc5c080,
    0xa220dc61,
    0x694b775a,
    0x161a121c,
    0xaba93e2,
    0xe52aa0c0,
    0x43e0223c,
    0x1d171b12,
    0xb0d090e,
    0xadc78bf2,
    0xb9a8b62d,
    0xc8a91e14,
    0x8519f157,
    0x4c0775af,
    0xbbdd99ee,
    0xfd607fa3,
    0x9f2601f7,
    0xbcf5725c,
    0xc53b6644,
    0x347efb5b,
    0x7629438b,
    0xdcc623cb,
    0x68fcedb6,
    0x63f1e4b8,
    0xcadc31d7,
    0x10856342,
    0x40229713,
    0x2011c684,
    0x7d244a85,
    0xf83dbbd2,
    0x1132f9ae,
    0x6da129c7,
    0x4b2f9e1d,
    0xf330b2dc,
    0xec52860d,
    0xd0e3c177,
    0x6c16b32b,
    0x99b970a9,
    0xfa489411,
    0x2264e947,
    0xc48cfca8,
    0x1a3ff0a0,
    0xd82c7d56,
    0xef903322,
    0xc74e4987,
    0xc1d138d9,
    0xfea2ca8c,
    0x360bd498,
    0xcf81f5a6,
    0x28de7aa5,
    0x268eb7da,
    0xa4bfad3f,
    0xe49d3a2c,
    0xd927850,
    0x9bcc5f6a,
    0x62467e54,
    0xc2138df6,
    0xe8b8d890,
    0x5ef7392e,
    0xf5afc382,
    0xbe805d9f,
    0x7c93d069,
    0xa92dd56f,
    0xb31225cf,
    0x3b99acc8,
    0xa77d1810,
    0x6e639ce8,
    0x7bbb3bdb,
    0x97826cd,
    0xf418596e,
    0x1b79aec,
    0xa89a4f83,
    0x656e95e6,
    0x7ee6ffaa,
    0x8cfbc21,
    0xe6e815ef,
    0xd99be7ba,
    0xce366f4a,
    0xd4099fea,
    0xd67cb029,
    0xafb2a431,
    0x31233f2a,
    0x3094a5c6,
    0xc066a235,
    0x37bc4e74,
    0xa6ca82fc,
    0xb0d090e0,
    0x15d8a733,
    0x4a9804f1,
    0xf7daec41,
    0xe50cd7f,
    0x2ff69117,
    0x8dd64d76,
    0x4db0ef43,
    0x544daacc,
    0xdf0496e4,
    0xe3b5d19e,
    0x1b886a4c,
    0xb81f2cc1,
    0x7f516546,
    0x4ea5e9d,
    0x5d358c01,
    0x737487fa,
    0x2e410bfb,
    0x5a1d67b3,
    0x52d2db92,
    0x335610e9,
    0x1347d66d,
    0x8c61d79a,
    0x7a0ca137,
    0x8e14f859,
    0x893c13eb,
    0xee27a9ce,
    0x35c961b7,
    0xede51ce1,
    0x3cb1477a,
    0x59dfd29c,
    0x3f73f255,
    0x79ce1418,
    0xbf37c773,
    0xeacdf753,
    0x5baafd5f,
    0x146f3ddf,
    0x86db4478,
    0x81f3afca,
    0x3ec468b9,
    0x2c342438,
    0x5f40a3c2,
    0x72c31d16,
    0xc25e2bc,
    0x8b493c28,
    0x41950dff,
    0x7101a839,
    0xdeb30c08,
    0x9ce4b4d8,
    0x90c15664,
    0x6184cb7b,
    0x70b632d5,
    0x745c6c48,
    0x4257b8d0,
  ];

  return AES;
};

// CommonJS module exports
if (typeof module !== "undefined" && typeof module.exports !== "undefined") {
  module.exports.AES = AES;
}
